#include "main_server.h"

#include "server_info.h"

#include "client_status.h"

using namespace evpp;

MainServer::MainServer(EventLoop* loop, const std::string& listenAddr, int thread_num)
: server_(nullptr)
, lock_()
, clients_()
, done_callback_(nullptr) {
    this->loop_ = loop;
    this->listen_addr_ = listenAddr;
    this->thread_num_ = thread_num;
}

MainServer::~MainServer() {
    if (server_ != nullptr) {
        server_->Stop();
        delete server_;
        server_ = nullptr;
    }
}

bool MainServer::IsRuning() const {
    return (server_ != nullptr) && (server_->IsRunning());
}


bool MainServer::Start() {

    server_ = new TCPServer(loop_, listen_addr_, "MainServer Class", thread_num_);
    server_->Init();

    server_->SetConnectionCallback([this](const TCPConnPtr& conn) {
        if (conn->IsConnected()) {
            this->onConnected(conn);
        }
        else {
            this->onDisconnected(conn);
        }
    });

    server_->SetMessageCallback(std::bind(&MainServer::onMessage, this, 
         std::placeholders::_1, std::placeholders::_2));

    return server_->Start();
}

bool MainServer::Stop() {
    if (server_ != nullptr) {
        server_->Stop(std::bind(&MainServer::onServerDone, this));
    }
    return true;
}

void MainServer::onConnected(const evpp::TCPConnPtr& conn) {
    //std::cout << conn->remote_addr() << " connected" << std::endl;
    ClientStatus* status = new ClientStatus();
    //status->last_tick = 
    conn->set_context(evpp::Any(status));
    ServerInfo::client_nums++;

    //conn->SetWriteCompleteCallback([](const evpp::TCPConnPtr& conn) {
    //    std::cout << "onWriteComplete." << std::endl;
    //});

    AddClient(conn);
}


void MainServer::onDisconnected(const evpp::TCPConnPtr& conn) {
    //std::cout << conn->remote_addr() << " disconnected" << std::endl;

    evpp::Any any = conn->context();
    ClientStatus* status = evpp::any_cast<ClientStatus*>(any);
    delete status;

    conn->set_context(evpp::Any(nullptr));
    ServerInfo::client_nums--;

    RemoveClient(conn);
}

void MainServer::onMessage(const evpp::TCPConnPtr& conn, evpp::Buffer* buf) {

    ServerInfo::recv_bytes += buf->length();
    conn->Send(buf);    
}


void MainServer::AddClient(const evpp::TCPConnPtr& conn) {
    lock_.lock();
    clients_[conn->id()] = conn;
    lock_.unlock();
}


void MainServer::RemoveClient(const evpp::TCPConnPtr& conn) {
    lock_.lock();
    clients_.erase(conn->id());
    lock_.unlock();
}

void MainServer::onServerDone() {
    if (server_) {
        delete server_;
        server_ = nullptr;
    }

    if (done_callback_)
        done_callback_();
}